package com.ydd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ydd.constant.JwtClaimsConstant;
import com.ydd.constant.MessageConstant;
import com.ydd.constant.StatusConstant;
import com.ydd.context.BaseContext;
import com.ydd.dto.*;
import com.ydd.entity.*;
import com.ydd.exception.AccountExistException;
import com.ydd.exception.AccountLockedException;
import com.ydd.exception.PasswordErrorException;
import com.ydd.mapper.*;
import com.ydd.pojo.dictsList;
import com.ydd.pojo.userInfo;
import com.ydd.properties.JwtProperties;
import com.ydd.service.IndexService;
import com.ydd.utils.JwtUtil;
import com.ydd.utils.CommonUntil;
import com.ydd.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.*;

@Service
@Slf4j
public class IndexServiceImpl implements IndexService {
    public static String hot="hot";


    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    JwtProperties jwtProperties;
    @Autowired
    SysDictMapper sysDictMapper;
    @Autowired
    MenuMapper menuMapper;
    @Autowired
    SysRoleMapper sysRoleMapper;
    @Autowired
    YddAdvimgMapper yddAdvimgMapper;
    @Autowired
    ArticleMapper articleMapper;
    @Autowired
    YddAdvposMapper yddAdvposMapper;
    @Autowired
    CateMapper cateMapper;
    @Autowired
    YddTagMapper yddTagMapper;
    @Autowired
    UserMapper userMapper; // ydd
    @Autowired
    YddLinkMapper yddLinkMapper;
    @Autowired
    SysConfigMapper sysConfigMapper;

    @Autowired
    UserArticleMapper userArticleMapper;

//    @Autowired
//    RedisTemplate redisTemplate;

    /**
     * 登录
     *
     * @param loginDTO
     * @return
     */
    @Override
    public JWtToken login(LoginDTO loginDTO) {
        String token;

        SysUser user = sysUserMapper.selectByUser(loginDTO);

        // 账户密码判定
        if (user == null) {
            // 用户不存在
            throw new PasswordErrorException(MessageConstant.ACCOUNT_NOT_FOUND);
        } else {
            // 密码MD5转换
            if (!DigestUtils.md5DigestAsHex(loginDTO.getPassword().getBytes()).equals(user.getPassword())) {
                throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
            } else {
                if (user.getStatus().equals(StatusConstant.DISABLE) ) {
                    //账号被锁定
                    throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
                } else {
                    // 开始生成token
                    Map<String, Object> claims = new HashMap<>();// 定义载荷
                    claims.put(JwtClaimsConstant.SYSUSER_ID, user.getId()); // 将登录成功的id传入令牌载荷
                    // 生成令牌
                    token = JwtUtil.createJWT(jwtProperties.getAdminSecretKey(), jwtProperties.getAdminTtl(), claims);
                }
            }
        }

        // 登录成功生成token
        JWtToken jWtToken = new JWtToken();
        jWtToken.setToken(token);
        return jWtToken;
    }


    /**
     * 获取用户资料
     *
     * @return
     */
    @Override
    public ProfileVO profile() {

        // dictList 获取配置详情表相关数据
        List<SysDict> sysDicts = sysDictMapper.All();
        HashMap<String, Object> interfaceType = new HashMap<>();
        HashMap<String, Object> orderType = new HashMap<>();
        HashMap<String, Object> reportType = new HashMap<>();
        HashMap<String, Object> tableType = new HashMap<>();
        HashMap<String, Object> theme = new HashMap<>();
        for (SysDict sysDict : sysDicts) {
            switch (sysDict.getType()) {
                case "interface_type":
                    interfaceType.put(sysDict.getValue(), sysDict.getLabel());
                    break;
                case "order_type":
                    orderType.put(sysDict.getValue(), sysDict.getLabel());
                    break;
                case "report_type":
                    reportType.put(sysDict.getValue(), sysDict.getLabel());
                    break;

                case "table_type":
                    tableType.put(sysDict.getValue(), sysDict.getLabel());
                    break;
                case "theme":
                    theme.put(sysDict.getValue(), sysDict.getLabel());
                    break;
            }
        }
        dictsList dictslist = dictsList.builder()
                .orderType(orderType)
                .interfaceType(interfaceType)
                .reportType(reportType)
                .tableType(tableType)
                .theme(theme)
                .build();


        // menuList
        List<SysMenu> smenuList = menuMapper.all();
        List<SysMenuChildVO> menuChList=new ArrayList<>();
        for (SysMenu sysMenu : smenuList) {
            SysMenuChildVO menuChildVO = new SysMenuChildVO();
            BeanUtils.copyProperties(sysMenu,menuChildVO);
            menuChList.add(menuChildVO);
        }
        Object[] menuList = menuChList.toArray();

        // userInfo
        String currentId = BaseContext.getCurrentId();
        userInfo userIofo = new userInfo();
        SysUser sysUser = sysUserMapper.selectById((BaseContext.getCurrentId()));
        BeanUtils.copyProperties(sysUser, userIofo);
        String roleId = sysUser.getRoleId();
        // 转换数组
        String[] roleIds = CommonUntil.String2Array(roleId);
        userIofo.setRoleId(roleIds);
        // 获取roleName数组
        List<String> list = new ArrayList();
        Object[] roleNames;
        for (String id : roleIds) {
            SysRole sysRole = sysRoleMapper.getById(id);
            list.add(sysRole.getName());
        }
        roleNames = list.toArray();

        userIofo.setRolename(roleNames);


        return ProfileVO.builder()
                .dictsList(dictslist)
                .btnList(new String[]{"*"})
                .userInfo(userIofo)
                .menuList(menuList)
                .build();
    }


    /**
     * 获取主页统计信息
     *
     * @return
     */
    @Override
    public BaseInfoVO baseInfo() {
        // 获取adminNum 管理员总数 "00cbde90-3c4a-11ec-abdc-7ba81cf6c5ef"
        SysUser sysUser = new SysUser();
        sysUser.setRoleId("1c54e003c1fc4dcd9b087ef8d48abac3");
        Integer adminNum = sysUserMapper.countByRoleId(sysUser);
        //获取advimgNum 广告图总数
        Integer advimgNum = yddAdvimgMapper.count();
        // 获取advposNum 广告位总数
        Integer advposNum = yddAdvposMapper.count();
        // 获取articleNum 文章总数
        Integer articleNum = articleMapper.count();
        // 获取cateNum 分类总数
        Integer cateNum = cateMapper.count();
        // 获取tagNum 标签总数
        Integer tagNum = yddTagMapper.count();


        // 获取 allCate 所有分类 及其name 分支文章数量 id
        YddCate[] allCateByDB = cateMapper.all();
        List<BaseInfoCateVO> baseInfoCateVOS = new ArrayList<>();
        for (YddCate yddCate : allCateByDB) {
            BaseInfoCateVO baseInfoCateVO = new BaseInfoCateVO();
            BeanUtils.copyProperties(yddCate, baseInfoCateVO);
            baseInfoCateVO.setNum(articleMapper.countByCate(yddCate.getId()));
            baseInfoCateVOS.add(baseInfoCateVO);
        }
        Object[] allCate = baseInfoCateVOS.toArray();


        // 获取 hotArticle 所有热门文章
        YddArticle[] hotArticle = articleMapper.hotArticles();
        // 获取 newUser 当日新增用户列表
        LambdaQueryWrapper<YddUser> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.orderByDesc(YddUser::getId).last("limit 7");
        Object[] newUser = userMapper.selectList(userLambdaQueryWrapper).toArray();
        // 获取 user相关数据
        YddUser yddUser = new YddUser();
        Integer userTotal = userMapper.count(yddUser);
        yddUser.setSex(1);
        Integer userMan = userMapper.count(yddUser);
        yddUser.setSex(0);
        Integer userWoman = userMapper.count(yddUser);

        BaseInfoUserVO baseInfoUserVO = BaseInfoUserVO.builder()
                .total(userTotal)
                .userMan(userMan)
                .userWoman(userWoman)
                .build();


        return BaseInfoVO.builder()
                .adminNum(adminNum)
                .advimgNum(advimgNum)
                .advposNum(advposNum)
                .allCate(allCate)
                .articleNum(articleNum)
                .cateNum(cateNum)
                .hotArticle(hotArticle)
                .newUser(newUser)
                .tagNum(tagNum)
                .user(baseInfoUserVO)
                .build();
    }


    /**
     * 获取热门指定文章数据
     *
     * @param page
     * @param limit
     * @return
     */
    @Override
    public FrontNewVO frontNewIndex(String page, String limit) {
        // desc 接口数据描述
        String desc = "首页数据大列表";
        // numDay 24小时最新文章数量
        QueryWrapper<YddArticle> articleQueryWrapper = new QueryWrapper<YddArticle>().gt("create_date", System.currentTimeMillis() - (1000 * 60 * 60 * 24));
        Integer numDay = articleMapper.selectCount(articleQueryWrapper);
        // numweek 一周文章最新数量
        articleQueryWrapper = new QueryWrapper<YddArticle>().gt("create_date", System.currentTimeMillis() - (1000 * 60 * 60 * 24 * 7));
        Integer numweek = articleMapper.selectCount(articleQueryWrapper);

        // list 数据列表
        FrontNewListDTO frontNewListDTO = new FrontNewListDTO();

        // 获取分页查询数据
        articleQueryWrapper = new QueryWrapper<>();
        articleQueryWrapper.orderByDesc("create_date");
        Page<YddArticle> articlePage = new Page<>(Long.valueOf(page), Long.valueOf(limit));
        articlePage = articleMapper.selectPage(articlePage, articleQueryWrapper);
        Integer pageSize = (int) articlePage.getSize();
        Integer totalPages = (int) articlePage.getTotal();
        List<YddArticle> records = articlePage.getRecords();

        List<FrontNewDataVO> frontNewListDTOList = new ArrayList<>();
        for (YddArticle article : records) {
            FrontNewDataVO dataDTO = new FrontNewDataVO();
            BeanUtils.copyProperties(article, dataDTO);
            YddCate yddCate = cateMapper.selectById(article.getCateid()); // 根据id查询分类名称
            dataDTO.setCatename(yddCate.getCatename()); // 封装
            frontNewListDTOList.add(dataDTO);
        }
        Object[] data = frontNewListDTOList.toArray();

        frontNewListDTO.setCount((int) articlePage.getSize());
        frontNewListDTO.setData(data);
        frontNewListDTO.setCurrentPage(Integer.valueOf(page));
        frontNewListDTO.setTotalPages(totalPages);
        frontNewListDTO.setPageSize(pageSize);

        return FrontNewVO.builder()
                .list(frontNewListDTO)
                .desc(desc)
                .numDay(numDay)
                .numWeek(numweek)
                .build();
    }


    /**
     * 获取首页和全局数据
     *
     * @return
     */
    @Override
    public FrontIndexVO frontIndexIndex() {
        // 获取allCate 所有分类
        YddCate[] allCate = cateMapper.all();
        //allLink 获取所有友情链接
        List<YddLink> yddLinks = yddLinkMapper.selectList(null);
        Object[] allLink = yddLinks.toArray();
        //allTag 所有标签
        List<YddTag> allTags = yddTagMapper.all();
        Object[] allTag = allTags.toArray();
        // banner 轮播图数据
        QueryWrapper<YddAdvimg> advimgQueryWrapper = new QueryWrapper<>();
        advimgQueryWrapper.eq("advimgpos", 15);
        List<YddAdvimg> YddAdvimgs = yddAdvimgMapper.selectList(advimgQueryWrapper);
        Object[] banner = YddAdvimgs.toArray();

        // config 所有分类
        // allData 配置数据
        List<SysConfig> sysConfigs = sysConfigMapper.all();
        Object[] allData = sysConfigs.toArray();
        // list 无用数据
        // 封装config
        FrontIndexConfigDTO config = FrontIndexConfigDTO.builder()
                .allData(allData)
                .build();

        // showBanner 侧边栏图片\
        advimgQueryWrapper = new QueryWrapper<>();
        advimgQueryWrapper.eq("advimgpos", 14);
        List<YddAdvimg> yddShowBanner = yddAdvimgMapper.selectList(advimgQueryWrapper);
        Object[] showBanner = yddShowBanner.toArray();

        // sideBanner 详情广告图
        advimgQueryWrapper = new QueryWrapper<>();
        advimgQueryWrapper.eq("advimgpos", 13);
        List<YddAdvimg> yddSideBanner = yddAdvimgMapper.selectList(advimgQueryWrapper);
        Object[] sideBanner = yddSideBanner.toArray();


        return FrontIndexVO.builder()
                .allLink(allLink)
                .allCate(allCate)
                .allTag(allTag)
                .banner(banner)
                .config(config)
                .showBanner(showBanner)
                .sideBanner(sideBanner)
                .build()
                ;
    }


    /**
     * 获取最近文章数据
     *
     * @return
     */
    @Override
    @Cacheable(value = "hotCache", key = "#root.methodName", unless = "#result==null") // 热点数据加入缓存
    public FrontHotVO frontNew() {
        // 生成desc
        String desc = "侧边栏最新文章";

        // 获取list数据 并封装
        LambdaQueryWrapper<YddArticle> articleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        articleLambdaQueryWrapper.orderByDesc(YddArticle::getCreateDate).last("limit 8");
        List<YddArticle> yddArticles = articleMapper.selectList(articleLambdaQueryWrapper);

        List<FrontNewDataVO> frontNewListDTOList = new ArrayList<>();
        for (YddArticle article : yddArticles) {
            FrontNewDataVO dataDTO = new FrontNewDataVO();
            BeanUtils.copyProperties(article, dataDTO);
            YddCate yddCate = cateMapper.selectById(article.getCateid()); // 根据id查询分类名称
            dataDTO.setCatename(yddCate.getCatename()); // 封装
            frontNewListDTOList.add(dataDTO);
        }
        Object[] list = frontNewListDTOList.toArray();


        return FrontHotVO.builder()
                .desc(desc)
                .list(list)
                .build();
    }


    /**
     * 获取最热文章数据
     *
     * @return
     */
    @Override
    @Cacheable(value = "recommendCache", key = "#root.methodName", unless = "#result==null") // 热点数据加入缓存
    public FrontHotVO frontRecommend() {
        // 生成desc
        String desc = "侧边推荐文章";

        // 获取list数据 并封装
        LambdaQueryWrapper<YddArticle> articleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        articleLambdaQueryWrapper.orderByDesc(YddArticle::getClick).last("limit 5");
        List<YddArticle> yddArticles = articleMapper.selectList(articleLambdaQueryWrapper);

        List<FrontNewDataVO> frontNewListDTOList = new ArrayList<>();
        for (YddArticle article : yddArticles) {
            FrontNewDataVO dataDTO = new FrontNewDataVO();
            BeanUtils.copyProperties(article, dataDTO);
            YddCate yddCate = cateMapper.selectById(article.getCateid()); // 根据id查询分类名称
            dataDTO.setCatename(yddCate.getCatename()); // 封装
            frontNewListDTOList.add(dataDTO);
        }
        Object[] list = frontNewListDTOList.toArray();


        return FrontHotVO.builder()
                .desc(desc)
                .list(list)
                .build();
    }


    /**
     * 文章详情
     *
     * @param id
     * @return
     */
    @Override
    public FrontShowVO frontshow(String id) {
        // info 文章详情数据


        YddArticle article = articleMapper.selectById(id);
        article.setClick(article.getClick()+1);
        articleMapper.updateById(article);

        FrontShowDTO info = new FrontShowDTO();
        BeanUtils.copyProperties(article,info);
        info.setCatename(cateMapper.selectById(article.getCateid()).getCatename());


        if (BaseContext.getUserCurrentId()!=null) {
            LambdaQueryWrapper<YddUserData> yddUserDataLambdaQueryWrapper=new LambdaQueryWrapper<>();
            yddUserDataLambdaQueryWrapper.
                    eq(YddUserData::getUserId,BaseContext.getUserCurrentId())
                    .eq(YddUserData::getArticleId,info.getId())
                    .eq(YddUserData::getType,"2");

            YddUserData likeYddUserData = userArticleMapper.selectOne(yddUserDataLambdaQueryWrapper);
            if (likeYddUserData!=null){
                info.setIsLike(true);
            }else {
                info.setIsLike(false);
            }

            yddUserDataLambdaQueryWrapper=new LambdaQueryWrapper<>();
            yddUserDataLambdaQueryWrapper.
                    eq(YddUserData::getUserId,BaseContext.getUserCurrentId())
                    .eq(YddUserData::getArticleId,info.getId())
                    .eq(YddUserData::getType,"1");
            likeYddUserData = userArticleMapper.selectOne(yddUserDataLambdaQueryWrapper);
            if (likeYddUserData!=null){
                info.setIsCollect(true);
            }else {
                info.setIsCollect(false);
            }
        }


        Integer[] ids = articleMapper.allId();
        int nowIdIndex = Arrays.binarySearch(ids, Integer.valueOf(id));
        // next 下一篇数据
        Object[] next = new Object[]{nowIdIndex == ids.length-1 ? "" : articleMapper.selectById(ids[nowIdIndex + 1])};

        // prev 上一篇数据
        Object[] prev = new Object[]{nowIdIndex == 0 ? "" : articleMapper.selectById(ids[nowIdIndex - 1])};
        //recommend 推荐文章数据

        LambdaQueryWrapper<YddArticle> eq = new LambdaQueryWrapper<YddArticle>().
                eq(YddArticle::getCateid, info.getCateid()).ne(YddArticle::getId,info.getId()).last("limit 8");

        Object[] recommend = articleMapper.selectList(eq).toArray();


        return FrontShowVO.
                builder()
                .info(info)
                .next(next)
                .prev(prev)
                .recommend(recommend)
                .build();
    }


    /**
     * 用户注册
     *
     * @param regDTO
     * @return
     */
    @Override
    public FrontRegVO reg(FrontRegDTO regDTO) {
        // userInfo
        LambdaQueryWrapper<YddUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(YddUser::getMobile, regDTO.getMobile());
        YddUser userinfo = userMapper.selectOne(lambdaQueryWrapper);
        if (userinfo != null) {
            log.info("用户已存在！");
            throw new AccountExistException(MessageConstant.ACCOUNT_EXISTS);
        } else {
            userinfo = new YddUser();
            userinfo.setMobile(regDTO.getMobile());
            userinfo.setUsername("优点达用户"+UUID.randomUUID().toString().substring(0,5));
            userinfo.setSex(0);
            userinfo.setDefaultData("1");
            userinfo.setAddress("尚未填写地址");
            userinfo.setIcon("/upload/initUsermg.jpg");
            userinfo.setNotes("这个人很懒，什么都没有写(●'◡'●)~");
            userinfo.setPassword(DigestUtils.md5DigestAsHex(regDTO.getPassword().getBytes()));
            userMapper.insert(userinfo);
        }

        // 生成令牌 token
        String token = CommonUntil.getToken(userinfo.getId(), jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl());


        return FrontRegVO.builder()
                .token(token)
                .collectNum(0)
                .articleNum(0)
                .zanNum(0)
                .userInfo(userinfo)
                .build();
    }


    /**
     * 文章列表数据
     *
     * @param frontListDTO
     * @return
     */
    @Override

    public indexlistDTO list(FrontListDTO frontListDTO) {
        Page<YddArticle> articlePage = new Page<YddArticle>(Long.valueOf(frontListDTO.getPage()), Long.valueOf(frontListDTO.getLimit()));

        LambdaQueryWrapper<YddArticle> articleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        articleLambdaQueryWrapper.eq(YddArticle::getCateid,frontListDTO.getCateid());
         articlePage = articleMapper.selectPage(articlePage, articleLambdaQueryWrapper);

        ArrayList<YddArticleVO> yddArticleVOS = new ArrayList<>();

        List<YddArticle> records = articlePage.getRecords();
        for (YddArticle record : records) {
            YddArticleVO yddArticleVO = new YddArticleVO();
            BeanUtils.copyProperties(record,yddArticleVO);
            yddArticleVO.setCatename(cateMapper.selectById(yddArticleVO.getCateid()).getCatename());
            yddArticleVOS.add(yddArticleVO);

        }


        return indexlistDTO.builder()
                .data(yddArticleVOS.toArray())
                .currentPage(articlePage.getCurrent())
                .pageSize(articlePage.getSize())
                .totalPages(articlePage.getTotal())
                .count(articlePage.getTotal()).
                build();
    }
}
